"""
L16设备数据模型
L16 Device Data Models

定义L16设备的所有数据模型和验证规则
Defines all data models and validation rules for L16 devices
"""

from typing import Optional, Literal, Dict, Any, Union
from pydantic import BaseModel, Field, validator, root_validator, model_validator
import base64
import binascii
from datetime import datetime, timezone


class L16BaseData(BaseModel):
    """
    L16基础数据模型
    L16 Base Data Model
    
    所有L16数据的基础结构
    Base structure for all L16 data
    """
    device_id: str = Field(..., description="设备唯一标识 / Device unique identifier")
    action: Literal["location", "health", "battery", "warning", "audio"] = Field(..., description="操作类型 / Action type")
    timestamp: int = Field(..., gt=0, description="时间戳 / Timestamp")

    class Config:
        extra = "allow"  # 允许额外字段 / Allow additional fields
        # 允许字段值为None时使用默认值 / Allow default values when field is None
        validate_assignment = True
        # 尝试类型转换 / Attempt type conversion
        use_enum_values = True
    
    @validator('device_id')
    def validate_device_id(cls, v):
        """验证设备ID格式 / Validate device ID format"""
        if not isinstance(v, str):
            v = str(v)
        
        # 移除空白字符 / Remove whitespace
        v = v.strip()
        
        # 检查长度和格式 / Check length and format
        if len(v) < 10 or len(v) > 20:
            raise ValueError('设备ID长度应在10-20位之间 / Device ID length should be between 10-20 characters')
        
        # 检查是否只包含数字和字母 / Check if contains only digits and letters
        if not v.replace('_', '').replace('-', '').isalnum():
            raise ValueError('设备ID只能包含字母、数字、下划线和连字符 / Device ID can only contain letters, numbers, underscores and hyphens')
        
        return v
    
    @validator('timestamp')
    def validate_timestamp(cls, v):
        """验证时间戳合理性 / Validate timestamp reasonableness"""
        if isinstance(v, str):
            try:
                v = int(v)
            except ValueError:
                raise ValueError('时间戳必须是整数 / Timestamp must be an integer')
        
        if v <= 0:
            raise ValueError('时间戳必须大于0 / Timestamp must be greater than 0')
        
        # 检查时间戳是否在合理范围内（2020年到2050年）/ Check if timestamp is in reasonable range (2020 to 2050)
        min_timestamp = int(datetime(2020, 1, 1, tzinfo=timezone.utc).timestamp())
        max_timestamp = int(datetime(2050, 1, 1, tzinfo=timezone.utc).timestamp())
        
        if v < min_timestamp or v > max_timestamp:
            raise ValueError(f'时间戳超出合理范围 / Timestamp out of reasonable range: {v}')
        
        return v


class L16LocationData(L16BaseData):
    """
    L16定位数据模型
    L16 Location Data Model
    
    处理L16设备的GPS定位信息
    Handles GPS location information from L16 devices
    """
    action: Literal["location"] = "location"
    longitude: float = Field(..., description="经度（高德坐标系）/ Longitude (AutoNavi coordinate system)")
    latitude: float = Field(..., description="纬度（高德坐标系）/ Latitude (AutoNavi coordinate system)")
    
    @validator('longitude', pre=True)
    def validate_longitude(cls, v):
        """验证经度范围 / Validate longitude range"""
        if v is None:
            raise ValueError('经度不能为空 / Longitude cannot be None')
        
        # 尝试类型转换 / Attempt type conversion
        if isinstance(v, str):
            try:
                v = float(v)
            except ValueError:
                raise ValueError(f'经度值无法转换为浮点数 / Longitude value cannot be converted to float: {v}')
        
        if not isinstance(v, (int, float)):
            raise ValueError('经度必须是数字 / Longitude must be a number')
        
        if not -180 <= v <= 180:
            raise ValueError(f'经度必须在-180到180之间 / Longitude must be between -180 and 180: {v}')
        
        return float(v)
    
    @validator('latitude', pre=True)
    def validate_latitude(cls, v):
        """验证纬度范围 / Validate latitude range"""
        if v is None:
            raise ValueError('纬度不能为空 / Latitude cannot be None')
        
        # 尝试类型转换 / Attempt type conversion
        if isinstance(v, str):
            try:
                v = float(v)
            except ValueError:
                raise ValueError(f'纬度值无法转换为浮点数 / Latitude value cannot be converted to float: {v}')
        
        if not isinstance(v, (int, float)):
            raise ValueError('纬度必须是数字 / Latitude must be a number')
        
        if not -90 <= v <= 90:
            raise ValueError(f'纬度必须在-90到90之间 / Latitude must be between -90 and 90: {v}')
        
        return float(v)


class L16HealthData(L16BaseData):
    """
    L16健康数据模型
    L16 Health Data Model
    
    处理L16设备的健康监测数据
    Handles health monitoring data from L16 devices
    """
    action: Literal["health"] = "health"
    heart_rate: int = Field(0, description="心率(次/分) / Heart rate (beats/min)")
    blood_oxygen: int = Field(0, description="血氧饱和度(%) / Blood oxygen saturation (%)")
    body_temperature: Optional[float] = Field(None, description="体温(°C) / Body temperature (°C)")
    blood_pressure_high: Optional[int] = Field(None, description="收缩压(mmHg) / Systolic pressure (mmHg)")
    blood_pressure_low: Optional[int] = Field(None, description="舒张压(mmHg) / Diastolic pressure (mmHg)")
    
    @validator('heart_rate', pre=True)
    def validate_heart_rate(cls, v):
        """验证心率数据 / Validate heart rate data"""
        if v is None:
            return 0
        
        if isinstance(v, str):
            try:
                v = int(float(v))  # 先转float再转int，处理"72.0"这样的情况
            except ValueError:
                return 0  # 转换失败返回默认值
        
        if not isinstance(v, (int, float)):
            return 0
        
        v = int(v)
        
        # 合理性检查，但不严格限制 / Reasonableness check without strict limits
        if v < 0:
            return 0
        if v > 500:  # 极端情况下的心率上限
            v = 500
            
        return v
    
    @validator('blood_oxygen', pre=True)
    def validate_blood_oxygen(cls, v):
        """验证血氧数据 / Validate blood oxygen data"""
        if v is None:
            return 0
        
        if isinstance(v, str):
            try:
                v = int(float(v))
            except ValueError:
                return 0
        
        if not isinstance(v, (int, float)):
            return 0
        
        v = int(v)
        
        if v < 0:
            return 0
        if v > 100:
            v = 100
            
        return v
    
    @validator('body_temperature', pre=True)
    def validate_body_temperature(cls, v):
        """验证体温数据 / Validate body temperature data"""
        if v is None or v == 0:
            return None
        
        if isinstance(v, str):
            try:
                v = float(v)
            except ValueError:
                return None
        
        if not isinstance(v, (int, float)):
            return None
        
        v = float(v)
        
        # 合理的体温范围 / Reasonable body temperature range
        if v < 30.0 or v > 50.0:
            return None  # 超出合理范围返回None
            
        return v
    
    @validator('blood_pressure_high', pre=True)
    def validate_blood_pressure_high(cls, v):
        """验证收缩压 / Validate systolic pressure"""
        if v is None or v == 0:
            return None
        
        if isinstance(v, str):
            try:
                v = int(float(v))
            except ValueError:
                return None
        
        if not isinstance(v, (int, float)):
            return None
        
        v = int(v)
        
        if v < 50 or v > 300:
            return None
            
        return v
    
    @validator('blood_pressure_low', pre=True)
    def validate_blood_pressure_low(cls, v):
        """验证舒张压 / Validate diastolic pressure"""
        if v is None or v == 0:
            return None
        
        if isinstance(v, str):
            try:
                v = int(float(v))
            except ValueError:
                return None
        
        if not isinstance(v, (int, float)):
            return None
        
        v = int(v)
        
        if v < 30 or v > 200:
            return None
            
        return v
    
    @model_validator(mode='after')
    def validate_blood_pressure_relationship(cls, values):
        """验证血压数据关系 / Validate blood pressure data relationship"""
        high = values.get('blood_pressure_high')
        low = values.get('blood_pressure_low')
        
        # 只有当两个值都存在且都大于0时才进行比较 / Only compare when both values exist and are greater than 0
        if high is not None and low is not None and high > 0 and low > 0:
            if high <= low:
                # 不抛出异常，而是调整数值 / Don't raise exception, adjust values instead
                values['blood_pressure_high'] = max(high, low + 10)
                values['blood_pressure_low'] = min(high - 10, low)
        
        return values


class L16BatteryData(L16BaseData):
    """
    L16电池和计步数据模型
    L16 Battery and Pedometer Data Model
    
    处理L16设备的电池状态和计步信息
    Handles battery status and pedometer information from L16 devices
    """
    action: Literal["battery"] = "battery"
    battery: int = Field(..., description="电池电量(%) / Battery level (%)")
    pedometer: int = Field(..., description="计步数 / Step count")
    
    @validator('battery', pre=True)
    def validate_battery(cls, v):
        """验证电池电量 / Validate battery level"""
        if v is None:
            return 0
        
        if isinstance(v, str):
            try:
                v = int(float(v))
            except ValueError:
                return 0
        
        if not isinstance(v, (int, float)):
            return 0
        
        v = int(v)
        
        # 确保在0-100范围内 / Ensure within 0-100 range
        if v < 0:
            return 0
        if v > 100:
            return 100
            
        return v
    
    @validator('pedometer', pre=True)
    def validate_pedometer(cls, v):
        """验证计步数 / Validate step count"""
        if v is None:
            return 0
        
        if isinstance(v, str):
            try:
                v = int(float(v))
            except ValueError:
                return 0
        
        if not isinstance(v, (int, float)):
            return 0
        
        v = int(v)
        
        # 步数不能为负数 / Step count cannot be negative
        if v < 0:
            return 0
        
        # 设置合理的上限（一天最多10万步）/ Set reasonable upper limit (max 100k steps per day)
        if v > 100000:
            v = 100000
            
        return v


class L16WarningData(L16BaseData):
    """
    L16预警数据模型
    L16 Warning Data Model
    
    处理L16设备的各种预警信息
    Handles various warning information from L16 devices
    """
    action: Literal["warning"] = "warning"
    type: int = Field(..., description="预警类型 / Warning type")
    longitude: Optional[Union[str, float]] = Field(None, description="预警位置经度 / Warning location longitude")
    latitude: Optional[Union[str, float]] = Field(None, description="预警位置纬度 / Warning location latitude")
    
    @validator('type', pre=True)
    def validate_warning_type(cls, v):
        """验证预警类型 / Validate warning type"""
        if v is None:
            raise ValueError('预警类型不能为空 / Warning type cannot be None')
        
        if isinstance(v, str):
            try:
                v = int(v)
            except ValueError:
                raise ValueError(f'预警类型必须是整数 / Warning type must be an integer: {v}')
        
        if not isinstance(v, int):
            raise ValueError('预警类型必须是整数 / Warning type must be an integer')
        
        # 扩展支持的预警类型 / Expand supported warning types
        valid_types = [1, 2, 13, 3, 4, 5]  # 添加更多可能的类型
        if v not in valid_types:
            # 不严格限制，记录日志但允许通过 / Not strictly limited, log but allow
            pass
            
        return v
    
    @validator('longitude', pre=True)
    def validate_warning_longitude(cls, v):
        """验证预警位置经度 / Validate warning location longitude"""
        if v is None or v == "" or v == "0":
            return None
        
        if isinstance(v, str):
            try:
                v = float(v)
            except ValueError:
                return None  # 转换失败返回None
        
        if isinstance(v, (int, float)):
            if -180 <= v <= 180:
                return str(v)  # 保持字符串格式以兼容现有系统
        
        return None
    
    @validator('latitude', pre=True)
    def validate_warning_latitude(cls, v):
        """验证预警位置纬度 / Validate warning location latitude"""
        if v is None or v == "" or v == "0":
            return None
        
        if isinstance(v, str):
            try:
                v = float(v)
            except ValueError:
                return None
        
        if isinstance(v, (int, float)):
            if -90 <= v <= 90:
                return str(v)
        
        return None
    


class L16AudioData(L16BaseData):
    """
    L16音频数据模型
    L16 Audio Data Model
    
    处理L16设备的音频录制数据
    Handles audio recording data from L16 devices
    """
    action: Literal["audio"] = "audio"
    audio: 'L16Audio' = Field(..., description="音频数据 / Audio data")


class L16Audio(BaseModel):
    """
    L16音频子模型
    L16 Audio Sub-model
    
    音频文件的具体结构
    Specific structure for audio files
    """
    voice: str = Field(..., description="音频文件BASE64编码 / Audio file BASE64 encoding")
    
    @validator('voice', pre=True)
    def validate_voice_base64(cls, v):
        """验证BASE64编码格式 / Validate BASE64 encoding format"""
        if v is None or v == "":
            raise ValueError('音频数据不能为空 / Audio data cannot be empty')
        
        if not isinstance(v, str):
            raise ValueError('音频数据必须是字符串 / Audio data must be a string')
        
        # 移除可能的空白字符 / Remove possible whitespace
        v = v.strip()
        
        if len(v) == 0:
            raise ValueError('音频数据不能为空 / Audio data cannot be empty')
        
        try:
            # 使用validate=True进行严格验证 / Use validate=True for strict validation
            decoded = base64.b64decode(v, validate=True)
            
            # 检查解码后的数据长度 / Check decoded data length
            if len(decoded) == 0:
                raise ValueError('音频数据解码后为空 / Audio data is empty after decoding')
                
            # 可选：检查是否是合理的音频文件头 / Optional: check for reasonable audio file headers
            # 这里可以添加更多的音频格式验证
                
        except (ValueError, binascii.Error) as e:
            raise ValueError(f'无效的BASE64编码音频数据 / Invalid BASE64 encoded audio data: {str(e)}')
        except Exception as e:
            raise ValueError(f'音频数据验证失败 / Audio data validation failed: {str(e)}')
        
        return v

    class Config:
        extra = "allow"


class L16DataModels:
    """
    L16数据模型集合
    L16 Data Models Collection
    
    提供所有L16数据模型的统一访问接口
    Provides unified access interface for all L16 data models
    """
    
    # 数据模型映射表 / Data model mapping table
    MODEL_MAPPING = {
        "location": L16LocationData,
        "health": L16HealthData,
        "battery": L16BatteryData,
        "warning": L16WarningData,
        "audio": L16AudioData
    }
    
    @classmethod
    def get_model(cls, action: str) -> Optional[BaseModel]:
        """
        根据操作类型获取对应的数据模型
        Get corresponding data model based on action type
        
        Args:
            action (str): 操作类型 / Action type
            
        Returns:
            Optional[BaseModel]: 数据模型类 / Data model class
        """
        return cls.MODEL_MAPPING.get(action)
    
    @classmethod
    def get_all_models(cls) -> Dict[str, BaseModel]:
        """
        获取所有数据模型
        Get all data models
        
        Returns:
            Dict[str, BaseModel]: 所有数据模型 / All data models
        """
        return cls.MODEL_MAPPING.copy()
    
    @classmethod
    def validate_action(cls, action: str) -> bool:
        """
        验证操作类型是否支持
        Validate if action type is supported
        
        Args:
            action (str): 操作类型 / Action type
            
        Returns:
            bool: 是否支持 / Whether supported
        """
        return action in cls.MODEL_MAPPING


# 更新L16AudioData模型以正确引用L16Audio
L16AudioData.model_rebuild()